-- 2022-8-8

---[[二进制文件
    -- 函数io.input和函数总是以文本方式(text mode)打开文件
    -- 在POSIX操作系统中 二进制文件和文本文件是没有差别的
    -- 然而 在其他一些像Windows之类的操作系统中 必须用特殊方式来打开二进制文件 即在io.open的模式字符串中使用字母b

    -- 通常 在读取二进制数据时 要么使用模式"a"来读取整个文件
    -- 要么使用模式n来读取n字节(在二进制文件中 行是没有意义的)
    -- 下面是一个简单的示例 他会把Windows格式的文本文件转换为POSIX格式 即把\r\n转换为\n
    do
        local inp = assert(io.open(arg[1],"rb"))
        local out = assert(io.open(arg[2],"wb"))
        local data = inp:read("a")
        data = string.gsub(data,"\r\n","\n")
        out:write(data)
        assert(out:close())
    end

    -- 由于标准I/O流(stdin/stdout)是以文本模式打开的 所以上例不能使用标准I/O流
    -- 相反 该程序假设输入和输出文件的名称是由程序的参数指定的
    -- 可以使用如下的命令调用该程序:
    -- lua prog.lua file.dos file.unix
    -- 再举一个例子 以下的程序输出了一个二进制文件中的所有字符串:
    do
        local f = assert(io.open(arg[1],"rb"))
        local data = f:read("a")
        local validchars = "[%g%s]"
        local pattern = "(" .. string.rep(validchars,6) .. "+)\0"
        for w in string.gmatch(data,pattern) do
            print(w)
        end
    end
    -- 这个程序假定字符串是一个以\0结尾的 包含6个和6个以上有效字符的序列 其中有效字符是指能与模式validchars匹配的任意字符串
    -- 在这个示例中 这个模式由可打印字符组成
    -- 我们使用函数string.rep和字符串连接创建用于捕获以\0结尾的 包含6个或6个以上有效字符validchars的模式 这个模式中的括号用于捕获不带\0的字符串

    --最后一个示例用于以十六进制内容输出二进制文件的Dump(结合书来看)
    do
        local f = assert(io.open(arg[1],"rb"))
        local blocksize = 16
        for bytes in f:lines(blocksize) do
            for i = 1, #bytes do
                local b = string.unpack("B",bytes,i)
                io.write(string.format("%02X",b))
            end
            io.write(string.rep("   ",blocksize - #bytes))
            bytes = string.gsub(bytes,"%c",".")
            io.write(" ",bytes,"\n")
        end
    end
    -- 同样 程序的第一个参数是输入文件名 结果则是被输出到标准输出中的普通文本
    -- 这个程序以16字节为一个块读取文件 对于每个块先输出每个字节的十六进制表示 然后将控制字符替换为点，最后把整个块作为文本输出
    -- 函数string.rep用于填充最后一行中的空白(因为最后一行往往不到16字节)以保持对齐
--]]